package k8;

import k8.util.LinkedList;

public abstract class Logic {

    private static LinkedList<Logic> logics = new LinkedList<Logic>();

    private static LinkedList.Node<Logic> curr;

    private static long time = 0;

    private static long elapsedtime = 0;

    private static long cycletime = 0;

    public String name;

    private long interval;

    private long nextupdate;

    private LinkedList.Node<Logic> listnode;

    /** Updates all Logics whos next update has past or is at the present time. */
    public static void updateAll() {
        // Do nothing when we have no Logics that wish to be updated
        if (logics.length() == 0)
            return;

        // Get the current and elapsed time and iterate Logics whos intervals
        // are less or equal to elapsed time
        elapsedtime = System.nanoTime() - time;
        cycletime += elapsedtime;
        time += elapsedtime;

        curr = null;
        while (true) {
            curr = logics.next(curr);

            if (curr == null) {
                cycletime = 0;
                break;
            }

            if (curr.item.interval > cycletime)
                break;

            if (curr.item.nextupdate <= time) {
                curr.item.update(time);
                curr.item.nextupdate += curr.item.interval;
            }
        }
    }

    /** Creates a new instance of Logic */
    public Logic() {
        interval = nextupdate = 0;
        setName(getClass().getName());
    }

    /**
     * Sets the name.
     * 
     * @param name
     *            the new name
     */
    public void setName(String name) {
        this.name = name;
    }

    /** Gets the name */
    public String getName() {
        return name;
    }

    /** Sets the number of updates to receive per second */
    public void setUpdateRate(float updates) {
        // Assign new interval
        if (updates == 0) {
            interval = nextupdate = 0;
        } else {
            interval = nextupdate = Math.round(1000000000 / updates);
        }

        // Remove from logics list
        logics.remove(listnode);

        // Leave node off logics list if interval is 0
        if (interval == 0) {
            listnode = null;
            return;
        }

        // If we have nothing yet then this becomes first and last
        if (logics.length() == 0) {
            listnode = logics.append(this);
            return;
        }

        // Do a quick check to see if its new position is at end of list.
        // Saves iterating the whole list.
        if (logics.last() != null && logics.last().item.interval <= interval) {
            listnode = logics.append(this);
            return;
        }

        // Otherwise prepend somewhere from first to last node
        LinkedList.Node<Logic> temp = null;
        while ((temp = logics.next(temp)) != null
                && temp.item.interval < interval)
            ;
        listnode = logics.prepend(temp, this);
    }

    /** Called n times a second, where n is defined by setUpdateRate(n) */
    public abstract void update(long time);

}
